# -*- coding: UTF-8 -*-
from django.core import meta

__all__ = ['auth', 'core']

# On modifie la variable __path__ de ce paquet de manière à ce que le code ultérieur
# puisse importer un modèle de données à partir de "django.models" même si le code
# de ce modèle de données ne réside pas physiquement en deça de django.models.
for mod in meta.get_installed_models():
    __path__.extend(mod.__path__)

# D'abord, on importe tous les modèles de données pour faire en sorte que les
# méta-classes se lancent.
modules = meta.get_installed_model_modules(__all__)

# On peut maintenant créer les méthodes supplémentaires qu'il était impossible
# de créer auparavant car toutes les relations n'étaient pas encore connues.
for mod in modules:
    for klass in mod._MODELS:

        # On ajoute des méthodes "get_truc", "get_truc_count" et "get_truc_list"
        # à tous les objets impliqués dans une relation.
        for rel_obj, rel_field in klass._meta.get_all_related_objects():
            # On détermine si l'objet se trouve dans une autre application.
            # Si c'est le cas, les noms de méthode se verront ajouter en préfixe
            # le label de l'application correspondante et les méthodes add_TRUC()
            # ne seront pas générées.
            rel_mod = rel_obj.get_model_module()
            rel_obj_name = klass._meta.get_rel_object_method_name(rel_obj, rel_field)
            if isinstance(rel_field.rel, meta.OneToOne):
                # On ajoute des méthodes "get_truc" aux objets impliqués dans une relation un-un.
                # EXEMPLE : Lieu.get_restaurants_restaurant()
                func = meta.curry(meta.method_get_related, 'get_object', rel_mod, rel_field)
                func.__doc__ = "Renvoie l'objet `%s.%s` associé." % (rel_obj.app_label, rel_obj.module_name)
                setattr(klass, 'get_%s' % rel_obj_name, func)
            elif isinstance(rel_field.rel, meta.ManyToOne):
                # On ajoute des méthodes "get_truc" aux objets impliqués dans une relation plusieurs-un.
                # EXEMPLE : Sondage.get_reponse()
                func = meta.curry(meta.method_get_related, 'get_object', rel_mod, rel_field)
                func.__doc__ = "Renvoie l'objet `%s.%s` associé qui correspond aux paramètres spécifiés." % (rel_obj.app_label, rel_obj.module_name)
                setattr(klass, 'get_%s' % rel_obj_name, func)
                # On ajoute des méthodes "get_truc_count" aux objets impliqués dans une relation plusieurs-un.
                # EXEMPLE : Sondage.get_reponse_count()
                func = meta.curry(meta.method_get_related, 'get_count', rel_mod, rel_field)
                func.__doc__ = "Renvoie le nombre d'objets `%s.%s` associés." % (rel_obj.app_label, rel_obj.module_name)
                setattr(klass, 'get_%s_count' % rel_obj_name, func)
                # On ajoute des méthodes "get_truc_list" aux objets impliqués dans une relation plusieurs-un.
                # EXEMPLE : Sondage.get_reponse_list()
                func = meta.curry(meta.method_get_related, 'get_list', rel_mod, rel_field)
                func.__doc__ = "Renvoie une liste des objets `%s.%s` associés." % (rel_obj.app_label, rel_obj.module_name)
                setattr(klass, 'get_%s_list' % rel_obj_name, func)
                # On ajoute des méthodes "add_truc" aux objets impliqués dans une relation plusieurs-un,
                # mais seulement pour les objets qui se trouvent dans la même application.
                # EXEMPLE : Sondage.add_reponse()
                if rel_obj.app_label == klass._meta.app_label:
                    func = meta.curry(meta.method_add_related, rel_obj, rel_mod, rel_field)
                    func.alters_data = True
                    setattr(klass, 'add_%s' % rel_obj_name, func)
                del func
            del rel_obj_name, rel_mod, rel_obj, rel_field # nettoyage

        # On fait de même pour tous les objets impliqués dans une relation plusieurs-plusieurs.
        for rel_opts, rel_field in klass._meta.get_all_related_many_to_many_objects():
            rel_mod = rel_opts.get_model_module()
            rel_obj_name = klass._meta.get_rel_object_method_name(rel_opts, rel_field)
            setattr(klass, 'get_%s' % rel_obj_name, meta.curry(meta.method_get_related_many_to_many, 'get_object', rel_mod, rel_field))
            setattr(klass, 'get_%s_count' % rel_obj_name, meta.curry(meta.method_get_related_many_to_many, 'get_count', rel_mod, rel_field))
            setattr(klass, 'get_%s_list' % rel_obj_name, meta.curry(meta.method_get_related_many_to_many, 'get_list', rel_mod, rel_field))
            if rel_opts.app_label == klass._meta.app_label:
                func = meta.curry(meta.method_set_related_many_to_many, rel_opts, rel_field)
                func.alters_data = True
                setattr(klass, 'set_%s' % rel_opts.module_name, func)
                del func
            del rel_obj_name, rel_mod, rel_opts, rel_field # nettoyage

        # On ajoute des méthodes "set_truc_order" et "get_truc_order" correspondant aux objets
        # qui doivent être triés en fonction de l'objet actuel.
        for obj in klass._meta.get_ordered_objects():
            func = meta.curry(meta.method_set_order, obj)
            func.__doc__ = "Définit l'ordre des objets `%s.%s` associés comme étant celui de la liste d'identifiants spécifiée." % (obj.app_label, obj.module_name)
            func.alters_data = True
            setattr(klass, 'set_%s_order' % obj.object_name.lower(), func)

            func = meta.curry(meta.method_get_order, obj)
            func.__doc__ = "Renvoie l'ordre des objets `%s.%s` associés sous forme d'une liste d'identifiants." % (obj.app_label, obj.module_name)
            setattr(klass, 'get_%s_order' % obj.object_name.lower(), func)
            del func, obj # nettoyage
        del klass # nettoyage
    del mod
del modules

# On expose get_app et get_module.
from django.core.meta import get_app, get_module
